package app.heatmap;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import app.heatmap.ids.SystemIds;
import app.heatmap.utils.L;

/**
 * @Copyright © 2019 EGuan Inc. All rights reserved.
 * @Description: 热图
 * @Version: 1.0
 * @Create: 2019/3/27 10:40
 * @Author: Wang-X-C
 */
public class HeatMap {

    private View decorView = null;
    private Context mContext = null;
    private boolean isRegister = false;

    public static HeatMap getInstance(Context context) {
        HeatMap.Holder.INSTANCE.initContext(context);
        return HeatMap.Holder.INSTANCE;
    }

    private void initContext(Context context) {
        if (mContext == null && context != null) {
            mContext = context.getApplicationContext();
        }
    }

    public void init() {
        if (!isRegister && !SystemIds.getInstance(mContext).isRegister()) {
            SystemIds.getInstance(mContext).parserId();
            final Application app = (Application) mContext.getApplicationContext();
            app.registerActivityLifecycleCallbacks(new SCallBack());
            isRegister = true;
        }

    }

    public void registerHeatMap(final Activity activity) {
        rootViewListener(activity);
        decorView = activity.getWindow().getDecorView();
        decorView.post(new Runnable() {
            @Override
            public void run() {
                decorView = activity.getWindow().getDecorView();
                hookDecorViewClick(activity, decorView);
            }
        });
    }

    private void rootViewListener(final Activity activity) {
        View view = activity.getWindow().getDecorView();
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    L.d("rootViewListener touch");
                    pageTouchInfo(activity, event, v);
                }
                return false;
            }
        });
    }

    /***
     * 递归调用
     *
     * @param activity
     * @param decorView
     */
    private void hookDecorViewClick(Activity activity, View decorView) {
        if (decorView instanceof ViewGroup) {
            hookViewClick(activity, decorView);
            int count = ((ViewGroup) decorView).getChildCount();
            for (int i = 0; i < count; i++) {
                if (((ViewGroup) decorView).getChildAt(i) instanceof ViewGroup) {
                    hookDecorViewClick(activity, ((ViewGroup) decorView).getChildAt(i));
                } else {
                    hookViewClick(activity, ((ViewGroup) decorView).getChildAt(i));
                }
            }
        } else {
            hookViewClick(activity, decorView);
        }
    }

    //  ========================================================================
    //  ========================================================================
    //  ========================================================================

    /**
     * 拦截需要使用View中的内部类android.view.View$ListenerInfo
     *
     * @param activity
     * @param view
     */
    public void hookViewClick(Activity activity, View view) {
        try {
            Class<?> viewClass = Class.forName("android.view.View");
            Method getListenerInfoMethod = viewClass.getDeclaredMethod("getListenerInfo");
            if (!getListenerInfoMethod.isAccessible()) {
                getListenerInfoMethod.setAccessible(true);
            }
            Object listenerInfoObject = getListenerInfoMethod.invoke(view);
            Class<?> mListenerInfoClass = Class.forName("android.view.View$ListenerInfo");
            Field mOnClickListenerField = mListenerInfoClass.getDeclaredField("mOnTouchListener");
            mOnClickListenerField.setAccessible(true);
            mOnClickListenerField.set(listenerInfoObject, new HeatMap.HeatMapTouchListener(
                    (View.OnTouchListener) mOnClickListenerField.get(listenerInfoObject), activity));
        } catch (Throwable e) {
        }
    }

    /**
     * touch事件处理
     *
     * @param activity
     * @param event
     * @param v
     */
    public void pageTouchInfo(final Activity activity, final MotionEvent event, final View v) {
        try {
            long time = System.currentTimeMillis();
            String pageUrl = activity.getClass().getName();

            DisplayMetrics metrics = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
            int width = metrics.widthPixels;
            int height = metrics.heightPixels;
            int dpi = metrics.densityDpi;
            float scale = 1.0f;
            View rootView = activity.getWindow().getDecorView().getRootView();
            rootView.setDrawingCacheEnabled(true);
            rootView.buildDrawingCache(true);
            Bitmap rawBitmap = rootView.getDrawingCache();
            if (rawBitmap != null) {
                final int rawDensity = rawBitmap.getDensity();
                scale = ((float) DisplayMetrics.DENSITY_DEFAULT) / rawDensity;
            }

            float rowX = event.getRawX();
            float rowY = event.getRawY();

            float x = event.getX();
            float y = event.getY();
            StringBuffer sb = new StringBuffer();
            sb.append("pageUrl:").append(pageUrl).append("; ").append("time:").append(time).append("; ")
                    .append("width:").append(width).append("; ").append("height:").append(height).append("; ")
                    .append("dpi:").append(dpi).append("; ").append("scale:").append(scale).append("; ").append("rowX:")
                    .append(rowX).append("; ").append("rowY:").append(rowY).append("; ").append("x:").append(x)
                    .append("; ").append("y:").append(y).append("; ")
                    // .append("view:").append(v.toString()).append("; ")
                    .append("pkgname:")

            ;
            int id = v.getId();
            sb.append(isSystemViewByViewId(id) ? "android" : "app");
            try {
                String typename = activity.getResources().getResourceTypeName(id);
                String entryname = activity.getResources().getResourceEntryName(id);
                sb.append("; ").append("typename:").append(typename).append("; ").append("entryname:")
                        .append(entryname);
            } catch (Throwable e) {
                L.v(e);
            }
            L.d("===>" + sb.toString());
            PathGeneral.getInstance().general(activity, v);
        } catch (Throwable e) {
            L.e(e);
        }
    }

    /**
     * @param id
     * @return true:系统组件 false:用户组件
     */
    public boolean isSystemViewByViewId(int id) {
        switch (id & 0xff000000) {
            case 0x7f000000:
                return false;
            case 0x01000000:
                return true;
            default:
                return false;
        }
    }

    private static class Holder {
        public static final HeatMap INSTANCE = new HeatMap();

    }

    public class HeatMapTouchListener implements View.OnTouchListener {

        private View.OnTouchListener onTouchListener;
        private Activity mActivity;

        public HeatMapTouchListener(View.OnTouchListener onTouchListener, Activity activity) {
            this.onTouchListener = onTouchListener;
            this.mActivity = activity;
        }

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                L.d("HeatMapTouchListener touch");
                pageTouchInfo(mActivity, event, v);
            }
            if (onTouchListener != null) {
                onTouchListener.onTouch(v, event);
            }
            return false;
        }
    }
}
